home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / HENSA / GRAPHICS / SPRite_TOOLS.ARC / c / spr_pal < prev    next >
Text File  |  1998-04-03  |  15KB  |  575 lines

  1. /************************************************************************
  2.  *                                                                      *
  3.  * spr_pal.c                                                            *
  4.  *                                                                      *
  5.  * Makes a sprite consisting of a !Paint style                          *
  6.  * palette for sprites <= 8 BPP, or for >8 BPP                          *
  7.  * a sprite with the colours sorted on value                            *
  8.  *                                                                      *
  9.  * Supports histogram option for all BPP                                *
  10.  *                                                                      *
  11.  * Version 2.12 (08-Mar-1994)                                           *
  12.  *                                                                      *
  13.  * (C) 1993/4 DEEJ Technology PLC                                       *
  14.  *                                                                      *
  15.  ************************************************************************/
  16.  
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include "io.h"
  21. #include "sprite.h"
  22. #include "process.h"
  23. #include "palette.h"
  24.  
  25. #define SIZE            16      /* palette sprite cell size            */
  26. #define HIST_MAX        1024    /* maximum number of bars in histogram */
  27. #define HEIGHT_MAX      768     /* maximum height of histogram sprite  */
  28.  
  29. /* globals */
  30.  
  31. FILE *inf, *outf, *errf;
  32. int  bytes;
  33. int  total;
  34. char string[256];
  35.  
  36.  
  37. /*
  38.  * Colour hue
  39.  *   1   256  512  768 1024 1280 1536
  40.  *   R    Y    G    C    B    M    R
  41.  * greys are 0
  42.  */
  43.  
  44. int hue(uint rgb)
  45. {
  46.         int add;
  47.         int b  = (rgb >> 24) &0xFF;
  48.         int g  = (rgb >> 16) &0xFF;
  49.         int r  = (rgb >>  8) &0xFF;
  50.         int c1 = 0;
  51.         int c2 = 0;
  52.  
  53.         /* exclude grey levels */
  54.  
  55.         if(r==g && r==b) return(0);
  56.  
  57.         /* find one/two dominant components */
  58.  
  59.         if((r>=g && g>=b) || (g>=r && r>=b))
  60.         {
  61.                 c1  = r - b;
  62.                 c2  = g - b;
  63.                 add = 256;
  64.         }
  65.     else
  66.     {
  67.             if((g>=b && b>=r) || (b>=g && g>=r))
  68.             {
  69.                     c1  = g - r;
  70.                     c2  = b - r;;
  71.                     add = 768;
  72.             }
  73.         else
  74.         {
  75.             /* must be */
  76.             /*
  77.                 if((b>=r && r>=g) || (r>=b && b>=g))
  78.             */
  79.                 {
  80.                         c1  = b - g;
  81.                         c2  = r - g;
  82.                         add = 1280;
  83.                 }
  84.         }
  85.     }
  86.  
  87.         /* scale components so largest is full range */
  88.  
  89.         if(c1 > c2)
  90.         {
  91.                 c2 = (c2*255)/c1;
  92.                 c1 = 255;
  93.         }
  94.         else
  95.         {
  96.                 c1 = (c1*255)/c2;
  97.                 c2 = 255;
  98.         }
  99.  
  100.         return( ((c2-c1) + add) % 1536 );
  101. }
  102.  
  103. /*
  104.  * qsort comparison function for 8-32 BPP pixels
  105.  * and pointers to hist_entry structures (bytes=8)
  106.  */
  107.  
  108. int compar(const void *vptr1, const void *vptr2)
  109. {
  110.         static int count  = 0;
  111.         uchar *ptr1 = (uchar*)vptr1;
  112.         uchar *ptr2 = (uchar*)vptr2;
  113.  
  114.         uint r,g,b;
  115.         uint val1, val2;
  116.         int  int1, int2;
  117.         int  hue1, hue2;
  118.  
  119.         switch(bytes)
  120.         {
  121.                 case 2:
  122.                         val1 = ptr1[0] + (ptr1[1] << 8);
  123.                         r    = (val1 >>  0) &0x1F; r = (r<<3) | (r>>2);
  124.                         g    = (val1 >>  5) &0x1F; g = (g<<3) | (g>>2);
  125.                         b    = (val1 >> 10) &0x1F; b = (b<<3) | (b>>2);
  126.                         val1 = (b<<24) | (g<<16) | (r<<8);
  127.  
  128.                         val2 = ptr2[0] + (ptr2[1] << 8);
  129.                         r    = (val2 >>  0) &0x1F; r = (r<<3) | (r>>2);
  130.                         g    = (val2 >>  5) &0x1F; g = (g<<3) | (g>>2);
  131.                         b    = (val2 >> 10) &0x1F; b = (b<<3) | (b>>2);
  132.                         val2 = (b<<24) | (g<<16) | (r<<8);
  133.                         break;
  134.  
  135.                 case 4:
  136.                         val1 = endian(LE, *(uint*)vptr1);
  137.                         val2 = endian(LE, *(uint*)vptr2);
  138.  
  139.             /* convert xxBBGGRR to BBGGRR00 */
  140.  
  141.             val1 = val1<<8;
  142.             val2 = val2<<8;
  143.             break;
  144.  
  145.         case 8:
  146.             val1 = (*((hist_entry**)vptr1))->value;
  147.             val2 = (*((hist_entry**)vptr2))->value;
  148.                         break;
  149.         }
  150.  
  151.         if((++count % (total/50))==0) fputc('.',errf);
  152.         
  153.         hue1 = hue(val1);
  154.         hue2 = hue(val2);
  155.         
  156.         if(hue1==hue2)
  157.         {
  158.                 int1 = intensity(val1);
  159.                 int2 = intensity(val2);
  160.  
  161.                 return(int1-int2);
  162.         }
  163.         else
  164.         {
  165.                 return(hue1-hue2);
  166.         }
  167. }
  168.  
  169. /*
  170.  * Make !Paint style palette sprite
  171.  * with different size but same BPP & palette
  172.  */
  173.  
  174. void palette_sprite(spr_info_str *spr)
  175. {
  176.         int  X,Y;
  177.         int  x1,y1;
  178.         int  x2,y2;
  179.         int  val;
  180.  
  181.         switch(spr->bpp)
  182.         {
  183.                 case 1: X =  2; Y =  1; break;
  184.                 case 2: X =  2; Y =  2; break;
  185.                 case 4: X =  4; Y =  4; break;
  186.                 case 8: X = 16; Y = 16; break;
  187.         }
  188.  
  189.         spr->X    = X * SIZE;
  190.         spr->Y    = Y * SIZE;
  191.         spr->Xasp = 1;
  192.         spr->Yasp = 1;
  193.  
  194.         fill_info(spr);
  195.         alloc_spr_data(spr);
  196.         memset(spr->spr_data, 0, spr->line_size*spr->Y);
  197.  
  198.         /* make !PAINT type palette grid */
  199.  
  200.         progress_start(string);
  201.  
  202.         for(y1=0; y1<Y; y1++)
  203.         for(x1=0; x1<X; x1++)
  204.         {
  205.                 /* palette entry index */
  206.  
  207.                 val = y1*Y+x1;
  208.  
  209.                 for(y2=1; y2<(SIZE-1); y2++)
  210.                 for(x2=1; x2<(SIZE-1); x2++)
  211.                 {
  212.                         write_pixel_val(spr,x1*SIZE+x2,y1*SIZE+y2,val);
  213.                 }
  214.                 progress(y1*Y+x1,X*Y);
  215.         }
  216.         write_sprite(spr, outf);
  217. }
  218.  
  219. /*
  220.  * Read sprite data and sort to give rougth palette display
  221.  */
  222.  
  223. void sort_sprite(spr_info_str *spr)
  224. {
  225.         int    x, y;
  226.         int    line_size;
  227.         uchar *line;
  228.  
  229.         /* set up globals */
  230.  
  231.         bytes = spr->pix/8;       /* bytes per pixel     */
  232.         total = spr->X*spr->Y*15; /* approx no. compares */
  233.  
  234.         /* sort cannot handle 3 byte values, so convert to 24/32 BPP */
  235.  
  236.         if(spr->pix == 24)
  237.         {
  238.                 line_size = spr->line_size;
  239.                 spr->pix  = 32;
  240.                 fill_info(spr);
  241.         }
  242.  
  243.         alloc_spr_data(spr);
  244.  
  245.         /* cannot read sprite data as is - must remove line padding */
  246.  
  247.         switch(bytes)
  248.         {
  249.             case 2:
  250.             case 4:
  251.                 for(y=0; y<spr->Y; y++)
  252.                 {
  253.                         fread(spr->spr_data + (y*spr->X*bytes),
  254.                               spr->line_size, 1, inf);
  255.                 }
  256.                 break;
  257.  
  258.             case 3:
  259.                 /* must be expanded to 32 BPP for sorting */
  260.  
  261.                 if((line=malloc(line_size))==0)
  262.                 {
  263.                         fprintf(stderr,"Unable to allocat line buffer\n");
  264.                         exit(1);
  265.                 }
  266.  
  267.                 for(y=0; y<spr->Y; y++)
  268.                 {
  269.                     fread(line, line_size, 1, inf);
  270.  
  271.                     for(x=0; x<spr->X; x++)
  272.                     {
  273.                         spr->spr_data[(((y*spr->X)+x)*4)+0] = line[x*3+0];
  274.                         spr->spr_data[(((y*spr->X)+x)*4)+1] = line[x*3+1];
  275.                         spr->spr_data[(((y*spr->X)+x)*4)+2] = line[x*3+2];
  276.                         spr->spr_data[(((y*spr->X)+x)*4)+3] = 0;
  277.                     }
  278.                 }
  279.                 bytes = 4;
  280.                 break;
  281.  
  282.             default:
  283.                 fprintf(errf,"Sorting not supported for %d BPP\n",spr->bpp);
  284.                 exit(2);
  285.                 break;
  286.         }
  287.  
  288.         progress_start(string);
  289.  
  290.         qsort((void*)spr->spr_data, spr->X*spr->Y, bytes, compar);
  291.  
  292.         write_sprite_header(spr, outf);
  293.  
  294.         /* write out with line padding */
  295.  
  296.         for(y=0; y<spr->Y; y++)
  297.         {
  298.                 fwrite(spr->spr_data + (y * spr->X * bytes),
  299.                        spr->line_size, 1, outf);
  300.         }
  301. }
  302.  
  303. /*
  304.  * produce a histogram sprite depicting
  305.  * colour use of original sprites data
  306.  */
  307.  
  308. void histogram_sprite(spr_info_str *spr, hist_info *h)
  309. {
  310.         hist_entry  *entry_ptr;
  311.     hist_entry **index;
  312.         int          x, y, x2, y2;
  313.         int          xsize, ysize;
  314.         int          xstep, ystep, yinc;
  315.         int          filter;
  316.     int         average;
  317.     uint         bg;
  318.         pix_str      col;
  319.         pix_str     *c;
  320.  
  321.         /* decide on a filter threshold to give < HIST_MAX pixels accross */
  322.  
  323.         filter = 0;
  324.         xsize  = h->colours;
  325.  
  326.         if(xsize > HIST_MAX)
  327.         {
  328.                 filter = 1;
  329.                 xsize  = h->more1;
  330.         }
  331.         if(xsize > HIST_MAX)
  332.         {
  333.                 filter = 10;
  334.                 xsize  = h->more10;
  335.         }
  336.         if(xsize > HIST_MAX)
  337.         {
  338.                 filter = 100;
  339.                 xsize  = h->more100;
  340.         }
  341.         if(xsize<h->more_frac && (xsize<256 || h->more_frac<HIST_MAX))
  342.         {
  343.                 filter = h->fraction;
  344.                 xsize  = h->more_frac;
  345.         }
  346.  
  347.         /* if small number of colours increase bar spacing */
  348.  
  349.         if(xsize <= (HIST_MAX/4))
  350.         {
  351.                 if(xsize <= (HIST_MAX/8))
  352.                         xstep = 4;
  353.                 else
  354.                         xstep = 2;
  355.         }
  356.         else
  357.         {
  358.                 xstep = 1;
  359.         }
  360.  
  361.     /* build index table for sorting from filtered histogram */
  362.  
  363.     if((index=(hist_entry**)malloc(xsize*sizeof(hist_entry_ptr)))==0)
  364.         {
  365.                 fprintf(stderr,"Unable to allocate index table\n");
  366.                 exit(1);
  367.         }
  368.  
  369.     x         = 0;
  370.     average   = 0;
  371.     entry_ptr = h->list_head;
  372.  
  373.     while(entry_ptr != 0)
  374.     {
  375.         if(entry_ptr->count > filter)
  376.         {
  377.             index[x++] = entry_ptr;
  378.             average   += entry_ptr -> count;
  379.         }
  380.         entry_ptr = entry_ptr->next;
  381.     }
  382.  
  383.     average /= xsize;
  384.  
  385.     /* integrity check */
  386.  
  387.     if(x != xsize)
  388.     {
  389.         fprintf(stderr, "Filtered count disagress with precalculated (%d,%d)\n", x, xsize);
  390.         exit(2);
  391.     }
  392.  
  393.         /*
  394.      * determine Y scale to give height < HEIGHT_MAX
  395.      * use maximum use from histogram and the average use
  396.          * AFTER filtering (rather than value from histogram)
  397.      */
  398.  
  399.     if(h->max_use > average*8)
  400.     {
  401.         ysize = average*8;
  402.     }
  403.     else
  404.     {
  405.             ysize = h->max_use;
  406.     }
  407.         ystep = 1;
  408.  
  409.         if(ysize > HEIGHT_MAX)
  410.         {
  411.                 ystep  = (ysize + HEIGHT_MAX-1)/HEIGHT_MAX;
  412.                 ysize /= ystep;
  413.         }
  414.  
  415.         fprintf(errf,"Filter      : %d\n",filter);
  416.         fprintf(errf,"Num of bars : %d\n",xsize);
  417.         fprintf(errf,"Y scale     : 1:%d\n",ystep);
  418.                 
  419.         spr->X    = xsize*xstep;
  420.         spr->Y    = ysize;
  421.         spr->Xasp = 1;
  422.         spr->Yasp = 1;
  423.  
  424.     /* sort index table */
  425.                     /* set up globals       */
  426.         bytes = 8;             /* comparison type flag */
  427.         total = xsize*20;       /* approx no. compares  */
  428.  
  429.     sprintf(string, "Sorting     :");
  430.         progress_start(string);
  431.  
  432.         qsort((void*)index, xsize, sizeof(hist_entry_ptr), compar);
  433.  
  434.     progress_finish();
  435.  
  436.         /* make sprite of appropriate size */
  437.  
  438.         fill_info(spr);
  439.         alloc_spr_data(spr);
  440.  
  441.     /* choose background colour and clear sprite */
  442.  
  443.     col.red   = 0;
  444.     col.green = 0;
  445.     col.blue  = 0;
  446.     c         = closest_rgb(spr, &col);
  447.  
  448.     switch(spr->bpp)
  449.     {    /* convert colour number to whole byte */
  450.         case 1:  bg = c->value * 0xFF; break;
  451.         case 2:  bg = c->value * 0x55; break;
  452.         case 4:  bg = c->value * 0x11; break;
  453.         case 8:  bg = c->value;        break;
  454.         default: bg = 0;               break;
  455.     }
  456.  
  457.         memset(spr->spr_data, bg, spr->line_size*spr->Y);
  458.  
  459.         /* plot histogram bars on sprite */
  460.  
  461.         sprintf(string,"Generating palette sprite:");
  462.         progress_start(string);
  463.  
  464.         entry_ptr = h->list_head;
  465.  
  466.         for(x=0; x<xsize; x++)
  467.         {
  468.                 col.value = index[x]->value;
  469.                 col.blue  = (col.value >> 24) & 0xFF;
  470.                 col.green = (col.value >> 16) & 0xFF;
  471.                 col.red   = (col.value >>  8) & 0xFF;
  472.  
  473.                 c = closest_rgb(spr, &col);
  474.  
  475.                 /* correct for background colour bar */
  476.  
  477.                 if(c->value == (int)bg)
  478.                 {
  479.                         col.red   = col.red   ^ 0xFF;
  480.                         col.green = col.green ^ 0xFF;
  481.                         col.blue  = col.blue  ^ 0xFF;
  482.                         c         = closest_rgb(spr, &col);
  483.                         yinc      = 2;
  484.                 }
  485.                 else
  486.                 {
  487.                         yinc      = 1;
  488.                 }
  489.  
  490.         x2 = xstep/2 + x*xstep;
  491.  
  492.                 if((index[x]->count/ystep) <= 1)
  493.                 {
  494.                         write_pixel_val(spr, x2, spr->Y-1, c->value);
  495.                 }
  496.                 else
  497.                 {
  498.             y2 = index[x]->count/ystep;
  499.             y2 = y2>=ysize ? ysize-1 : y2;
  500.  
  501.                         for(y=0; y<y2; y+=yinc)
  502.                         {
  503.                                 write_pixel_val(spr, x2, spr->Y-y-1, c->value);
  504.                         }
  505.                 }
  506.  
  507.                 progress(x, xsize);
  508.         }
  509.  
  510.         write_sprite(spr, outf);
  511. }
  512.                 
  513.  
  514. int main(int argc, char **argv)
  515. {
  516.         BOOL         histogram = FALSE;
  517.         hist_info    *hist;
  518.         spr_info_str spr;
  519.  
  520.         if(argc>1 && argv[1][0]=='-')
  521.         {
  522.                 if(argv[1][1] == 'h')
  523.                 {
  524.                         histogram = TRUE;
  525.                 }
  526.                 else
  527.                 {
  528.                         fprintf(errf,"Unrecognised flag '%s'\n",argv[1]);
  529.                         return(1);
  530.                 }
  531.                 argc--; argv++;
  532.         }
  533.  
  534.         file_args(argc, argv, &inf, &outf, &errf);
  535.  
  536.         /* read sprite from file */
  537.  
  538.         read_sprite_header(&spr, inf);    
  539.  
  540.         sprintf(string,"Generating palette sprite:");
  541.  
  542.         if(histogram)
  543.         {
  544.                 /* read sprite & build histogram of colour usage */
  545.  
  546.                 alloc_spr_data(&spr);
  547.                 fread(spr.spr_data, spr.line_size, spr.Y, inf);
  548.  
  549.                 hist = build_histogram(&spr);
  550.  
  551.                 /* free orginal sprite data and make a histogram image */
  552.  
  553.                 free((void*)spr.spr_data);
  554.  
  555.                 histogram_sprite(&spr, hist);
  556.         }
  557.         else
  558.         {
  559.                 if(spr.bpp <= 8)
  560.                 {
  561.                         palette_sprite(&spr);
  562.                 }
  563.                 else
  564.                 {
  565.                         sort_sprite(&spr);
  566.                 }
  567.         }
  568.  
  569.         progress_finish();
  570.  
  571.         fclose(inf);
  572.         fclose(outf);
  573.         fclose(errf);
  574. }
  575.